<template>
  <view class="pattern-lock">
    <canvas 
      :canvas-id="canvasId"
      class="lock-canvas"
      @touchstart="onTouchStart"
      @touchmove="onTouchMove"
      @touchend="onTouchEnd"
    ></canvas>
    <text class="message">{{ message }}</text>
  </view>
</template>

<script>
export default {
  props: {
    loading: Boolean
  },
  data() {
    return {
      canvasId: 'lockCanvas',
      ctx: null,
      points: [],
      selected: [],
      r: 30, // 圆点半径
      currentPos: null,
      firstPattern: '',
      mode: 'verify', // set / confirm / verify
      message: '',
      isDrawing: false
    }
  },
  mounted() {
    this.initCanvas()
    this.checkPatternStorage()
  },
  methods: {
    checkPatternStorage() {
      const saved = uni.getStorageSync('patternLock')
      if (!saved) {
        this.mode = 'set'
        this.message = '首次设置图案密码'
      } else {
        this.mode = 'verify'
        this.message = '请输入图案密码'
      }
    },
    initCanvas() {
      const query = uni.createSelectorQuery().in(this)
      query.select('.lock-canvas').boundingClientRect().exec(res => {
        const size = res[0].width
        this.ctx = uni.createCanvasContext(this.canvasId, this)
        this.buildPoints(size)
        this.draw()
      })
    },
    buildPoints(size) {
      this.points = []
      const gap = size / 4
      for (let row = 0; row < 3; row++) {
        for (let col = 0; col < 3; col++) {
          this.points.push({
            x: gap * (col + 1),
            y: gap * (row + 1),
            index: row * 3 + col
          })
        }
      }
    },
    draw() {
      const ctx = this.ctx
      ctx.clearRect(0, 0, 1000, 1000)

      // draw lines
      if (this.selected.length) {
        ctx.beginPath()
        ctx.setStrokeStyle('#00f')
        ctx.setLineWidth(3)
        ctx.moveTo(this.selected[0].x, this.selected[0].y)
        for (let i = 1; i < this.selected.length; i++) {
          ctx.lineTo(this.selected[i].x, this.selected[i].y)
        }
        if (this.isDrawing && this.currentPos) {
          ctx.lineTo(this.currentPos.x, this.currentPos.y)
        }
        ctx.stroke()
        ctx.closePath()
      }

      // draw circles
      this.points.forEach(p => {
        ctx.beginPath()
        const isSelected = this.selected.some(s => s.index === p.index)
        ctx.setFillStyle(isSelected ? '#00f' : '#aaa')
        ctx.arc(p.x, p.y, this.r, 0, Math.PI * 2)
        ctx.fill()
        ctx.closePath()
      })

      ctx.draw()
    },
    getTouchPos(e) {
      const touch = e.touches[0]
      return { x: touch.x, y: touch.y }
    },
    getPointAt(pos) {
      return this.points.find(p => {
        return Math.hypot(p.x - pos.x, p.y - pos.y) < this.r
      })
    },
    onTouchStart(e) {
      if (this.loading) return
      const pos = this.getTouchPos(e)
      const p = this.getPointAt(pos)
      if (p) {
        this.selected = [p]
        this.isDrawing = true
      }
      this.draw()
    },
    onTouchMove(e) {
      if (!this.isDrawing || this.loading) return
      const pos = this.getTouchPos(e)
      const p = this.getPointAt(pos)
      if (p && !this.selected.find(s => s.index === p.index)) {
        this.selected.push(p)
      }
      this.currentPos = pos
      this.draw()
    },
    onTouchEnd() {
      if (!this.isDrawing || this.loading) return
      this.isDrawing = false
      this.currentPos = null
      this.draw()
      const pattern = this.selected.map(p => p.index).join('-')
      this.handlePattern(pattern)
    },
    handlePattern(pattern) {
      if (pattern.length < 4) {
        this.message = '至少连接4个点'
        this.reset()
        return
      }

      if (this.mode === 'set') {
        this.firstPattern = pattern
        this.mode = 'confirm'
        this.message = '请再次绘制以确认图案'
        this.reset()
      } else if (this.mode === 'confirm') {
        if (pattern === this.firstPattern) {
          uni.setStorageSync('patternLock', pattern)
          this.message = '图案设置成功'
          this.$emit('complete', pattern)
        } else {
          this.message = '两次图案不一致，请重新设置'
          this.mode = 'set'
        }
        this.reset()
      } else if (this.mode === 'verify') {
        const saved = uni.getStorageSync('patternLock')
        if (pattern === saved) {
          this.message = '解锁成功'
          this.$emit('complete', pattern)
        } else {
          this.message = '图案错误，请重试'
        }
        this.reset()
      }
    },
    reset() {
      setTimeout(() => {
        this.selected = []
        this.draw()
      }, 500)
    }
  }
}
</script>

<style scoped>
.pattern-lock {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.lock-canvas {
  width: 300px;
  height: 300px;
  background-color: #f5f5f5;
  border-radius: 8px;
}
.message {
  margin-top: 20rpx;
  font-size: 28rpx;
  color: #fff;
}
</style>
